#ifndef COLLISION_H
#define COLLISION_H

#include "sprite_handler.h"

#include "characters/characters.h"

// function prototypes

void handleCollisions();
CharacterType hasCollision( int const x, int const y );

typedef struct STRUCT_RECTANGLE
{
	int left, top;
	int right, bottom;
} Rectangle;

// static function prototypes

static BOOL isColliding ( Rectangle const curr_box, Rectangle const target_box );
static BOOL contains( Rectangle const box, int const x, int const y );
// static void resolveCollision( Rectangle * a, Rectangle * b, ResolveParam const resolve_param );

void handleCollision( SpriteHandler *, SpriteHandler * );
BOOL getMapCoordinates( SpriteHandler const * sprite, int *, int * );

// Handle all collisions occuring between all sprites in the game
void handleCollisions()
{
	int i;
	for ( i = 0 ; i < MAX_SPRITES ; ++i )
	{
		SpriteHandler * curr_sprite = &g_spriteHandlers[ i ];
		
		Rectangle curr_box;		// collision box for current sprite
		
		// Make sure we have map coordinates for this sprite, if not, don't perform collision detection on it
		if ( !curr_sprite->alive || ! getMapCoordinates( curr_sprite, &curr_box.left, &curr_box.top ) )
		{
			continue;
		}
		
		// Set the right and bottom fields for current sprites collision box
		curr_box.right = curr_box.left + GetSpriteWidth( curr_sprite );
		curr_box.bottom = curr_box.top + GetSpriteHeight( curr_sprite );
		
		int j;
		for ( j = i + 1 ; j < MAX_SPRITES ; ++j )
		{
			// Calculate any collisions these two sprite handlers could have
			SpriteHandler * target_sprite = &g_spriteHandlers[ j ] ;
						
			Rectangle target_box;	// collision box for target sprite
			
			// Make sure we have map coordinates for this sprite, if not, don't perform collision detection on it
			if ( !target_sprite->alive || !getMapCoordinates( target_sprite, &target_box.left, &target_box.top ) )
			{
				continue;
			}
			
			// Set the right and bottom fields for current sprites collision box
			target_box.right = target_box.left + GetSpriteWidth( target_sprite );
			target_box.bottom = target_box.top + GetSpriteHeight( target_sprite );
			
			// If collision occurs between these two sprites then
			if ( isColliding( curr_box, target_box ) )
			{
				// go to the handler collision function, passing both as args
				handleCollision( curr_sprite, target_sprite );
			}
		}		
	}
}

CharacterType hasCollision( int const x, int const y )
{
	int i;
	for ( i = 0 ; i < MAX_SPRITE_HANDLERS ; ++i )
	{
		SpriteHandler * curr_sprite = &g_spriteHandlers[ i ];
		
		Rectangle curr_box;	// collision box for current sprite
		
		// Make sure we have map coordinates for this sprite, if not, don't perform collision detection on it
		if ( ! curr_sprite->alive || ! getMapCoordinates( curr_sprite, &curr_box.left, &curr_box.top ) )
		{
			continue;
		}
		
		// Set the right and bottom fields for current sprites collision box
		curr_box.right = curr_box.left + GetSpriteWidth( curr_sprite );
		curr_box.bottom = curr_box.top + GetSpriteHeight( curr_sprite );
		
		if ( contains( curr_box, x, y ) )
		{
			return curr_sprite->characterType;
		}
	}
	
	return CHAR_NONE;
}

// Returns true if two sprites are colliding
static BOOL isColliding ( Rectangle const curr_box, Rectangle const target_box )
{
	// Perform checks for each corner of the target sprite on the current sprite
	if ( contains( curr_box, target_box.left, target_box.top ) ||
		 contains( curr_box, target_box.left, target_box.bottom ) ||
		 contains( curr_box, target_box.right, target_box.top ) ||
		 contains( curr_box, target_box.right, target_box.bottom ) )
	{
		return true;
	}
	// perform same operations from the point of view of the target sprite
	// this will make sure a collision is found if the target sprite is bigger than
	// the current sprite and the intersection occurs between two points
	else if ( contains( target_box, curr_box.left, curr_box.top ) ||
			  contains( target_box, curr_box.left, curr_box.bottom ) ||
			  contains( target_box, curr_box.right, curr_box.top ) ||
			  contains( target_box, curr_box.right, curr_box.bottom ) )
	{
		return true;
	}
	
	return false;
}

static BOOL contains( Rectangle const box, int const x, int const y )
{
	if ( box.left < x && x < box.right &&
		 box.top < y && y < box.bottom )
	{
		return true;
	}
	
	return false;
}

// This function pushes the two sprite handlers away from eachtother to resolve the collision
// static void resolveCollision( Rectangle * a, Rectangle * b, ResolveParam const resolve_param )
// {
	// // Find the minimum distance we need to push the sprites so they are not colliding->
	
	// // find the center points of the rectangles
	// int a_center_x, a_center_y;
	// int b_center_x, b_center_y;
	
	// a_center_x = ( a->right - a->left ) / 2 + a->left;
	// a_center_y = ( a->bottom - a->top ) / 2 + a->top;
	
	// b_center_x = ( b->right - b->left ) / 2 + b->left;
	// b_center_y = ( b->bottom - b->top ) / 2 + b->top;
	
	// // if a is to the right of b
	// if ( a_center_x < b_center_x )
	// {
		// // if a is above b
		
		// // if a is below b
	// }
	// else if ( a_center_x > b_center_x ) // if b is to the right of a
	// {	
		// // if a is above b
		
		// // if a is below b
	// }
	// else
	// {
	// }
// }

#endif
